pub mod auth_middleware;
pub mod error_middleware;
mod print;
pub use print::print_params;

use crate::Error;
use anyhow::Result;
use axum::body::to_bytes;
use axum::extract::Request;
use axum::middleware::Next;
use axum::response::{IntoResponse, Response};
use std::future::Future;
use std::pin::Pin;

/// 通过[axum::middleware::from_fn()]函数创建中间件
///
/// `from_fn` 需要赋予
///
/// 1. 是一个async函数.
/// 2. 有零个或多个 [FromRequestParts] 提取器。
/// 3. 将一个 [FromRequest] 提取器作为倒数第二个参数。
/// 4. 将 [Next](Next) 作为最后一个参数
/// 5. 返回类型需要实现 [IntoResponse].
///
/// 全局错误处理中间件
pub async fn error_middleware(req: Request, next: Next) -> Response {
    let path = req.uri().path();
    log::info!("访问路径: {path}");
    let resp = next.run(req).await;
    let code = resp.status();
    if code.is_success() {
        resp
    } else {
        let res = body_2_string(resp).await;
        if let Ok(err_msg) = res {
            log::error!("错误信息: {err_msg}")
        }
        let msg = status_desc(code.as_u16());
        Error::Business(msg).into_response()
    }
}

/// 将响应体转成 [String]
async fn body_2_string(response: Response) -> Result<String> {
    let body = response.into_body();
    let bytes = to_bytes(body, usize::MAX).await?;
    let body = String::from_utf8(bytes.to_vec())?;
    Ok(body)
}

/// 通过[axum::middleware::from_fn()]函数创建中间件
///
/// 认证中间件
pub async fn auth_middleware(req: Request, next: Next) -> Response {
    let auth = req
        .headers()
        .get("token")
        .and_then(|header| header.to_str().ok())
        .is_some_and(|token| token == "token");
    if auth {
        next.run(req).await
    } else {
        Error::Token.into_response()
    }
}

type PinBox<Resp, Err> = Pin<Box<dyn Future<Output = Result<Resp, Err>> + Send + 'static>>;

macro_rules! status_codes_desc {
    (
        $(
            ($num:expr,  $phrase:literal);
        )+
    ) => {
        /// 返回部分状态码返回中文描述
        fn status_desc(num: u16) -> String {
            match num {
                $(
                $num => String::from($phrase),
                )+
                _ => {
                    let  code = axum::http::StatusCode::from_u16(num);
                    if let Err(_) = code {
                        return String::from("操作失败");
                    }
                    let reason = code.unwrap().canonical_reason();
                    match reason {
                        Some(reason) => String::from(reason),
                        None => String::from("操作失败")
                    }
                }
            }
        }
    }
}

status_codes_desc!(
    (400,  "错误的请求");
    (403,  "服务器拒绝请求");
    (404,  "资源不存在");
    (405,  "请求方法不允许");
    (422,  "请求参数错误");
    (500,  "服务器内部错误");
    (502,  "错误网关");
    (503,  "服务不可用");
    (504,  "网关超时");
);
